#include "Infos_audio.h"
#include "FFMpegInit.h"
#include <iostream>
#include <slimthread.h>
//______________________________________________________________________________
//______________________________________________________________________________
//______________________________________________________________________________
void Info_buffer_audio_Init (Info_buffer_audio *iba) {
 //iba->buf  = NULL;
 iba->size = 0;
 iba->deb  = 0;
 iba->duration = 0;
 iba->buffer = NULL;
}

//______________________________________________________________________________
void Info_buffer_audio_Maj(Info_buffer_audio *iba, unsigned int s, unsigned int d) {
 iba->size = s;
// iba->buf  = b;
 iba->deb  = d;
}

//______________________________________________________________________________
void Info_buffer_audio_Copy(Info_buffer_audio *iba, const Info_buffer_audio *src) {
 iba->size = src->size;
// iba->buf  = src->buf;
 iba->deb  = src->deb;
}

//______________________________________________________________________________
//______________________________________________________________________________
//______________________________________________________________________________
// For sound callback
void Info_for_sound_CB_Init(Info_for_sound_CB *ifscb, Mutex *m)  {
 ifscb->mutex = m; 
 ifscb->first = ifscb->last = ifscb->last_temp = ifscb->nb = ifscb->size_buffers = ifscb->delta_buffers_temp = 0; 
 ifscb->nb_buffers = ALX_INFO_BUFFER_AUDIO_NB_BUFFER;
 for(unsigned int i = 0; i<ifscb->nb_buffers; i++)
  {Info_buffer_audio_Init( &(ifscb->Tab_wav[i]) );}
 ifscb->s_SynchronisationThreshold = 0.15;
 ifscb->last_buffer_index = 0;
 ifscb->first_t = 0;
 ifscb->num_last_buffer = 0;
}

//______________________________________________________________________________
void Info_for_sound_CB_Commit_buffers(Info_for_sound_CB *ifscb) {
	Info_for_sound_CB_Lock(ifscb);
		//printf("\t<commit at %d>\n", clock());
		ifscb->nb += ifscb->last_temp - ifscb->last;
		if(ifscb->last_temp < ifscb->last) {ifscb->nb += ALX_INFO_BUFFER_AUDIO_NB_BUFFER;}
		ifscb->last = ifscb->last_temp;
		ifscb->size_buffers += ifscb->delta_buffers_temp;
		ifscb->delta_buffers_temp = 0;
	Info_for_sound_CB_UnLock(ifscb);
}

//______________________________________________________________________________
Mutex* Info_for_sound_CB_Get_mutex (Info_for_sound_CB *ifscb) {return ifscb->mutex;}

//______________________________________________________________________________
const unsigned int Info_for_sound_CB_Nb_buffers(Info_for_sound_CB *ifscb) {return ifscb->nb_buffers;}

//______________________________________________________________________________
const unsigned int Info_for_sound_CB_Nb_pkt    (Info_for_sound_CB *ifscb) {return ifscb->nb;}

//______________________________________________________________________________
const unsigned int Info_for_sound_CB_Size_buffers(Info_for_sound_CB *ifscb) {return ifscb->size_buffers;}

//______________________________________________________________________________
void Info_for_sound_CB_Put_New(Info_for_sound_CB *ifscb, const void *buf_src, const int size, const int64_t pts, const int64_t dts, const int duration)
{if(ifscb->nb >= ALX_INFO_BUFFER_AUDIO_NB_BUFFER) {std::cout << "\n________\nOVERLOAD!\n";}
 ifscb->delta_buffers_temp += size;
   ifscb->Tab_wav[ifscb->last_temp].size     = size;
   ifscb->Tab_wav[ifscb->last_temp].pts      = pts;
   ifscb->Tab_wav[ifscb->last_temp].dts      = dts;
   ifscb->Tab_wav[ifscb->last_temp].duration = duration;

   if(ifscb->last_buffer_index + size >= ALX_INFO_BUFFER_AUDIO_TAILLE_BUFFER)
    {ifscb->Tab_wav[ifscb->last_temp].deb    = 0;
     ifscb->Tab_wav[ifscb->last_temp].buffer = ifscb->internal_buffer;
     ifscb->last_buffer_index           = size;
	 //std::cout << "AUDIO CYCLE\n";
    } else {ifscb->Tab_wav[ifscb->last_temp].deb    = 0;
            ifscb->Tab_wav[ifscb->last_temp].buffer = ifscb->internal_buffer + ifscb->last_buffer_index;
			ifscb->last_buffer_index          += size;
           }
   memcpy(ifscb->Tab_wav[ifscb->last_temp].buffer, buf_src, size);
 ifscb->last_temp = (ifscb->last_temp+1)%ifscb->nb_buffers;
 // ifscb->nb++; // XXX DEBUG
}

/*
//______________________________________________________________________________
const double Info_for_sound_get_Synchronisation_threshold(const Info_for_sound_CB *ifscb)   {return ifscb->s_SynchronisationThreshold;}
//______________________________________________________________________________
void Info_for_sound_set_Synchronisation_threshold(Info_for_sound_CB *ifscb, double v) {ifscb->s_SynchronisationThreshold = v;}
*/

//______________________________________________________________________________
void Info_for_sound_CB_Release(Info_for_sound_CB *ifscb) {
 //if(ifscb->Tab_wav[ifscb->first].buf) {free(ifscb->Tab_wav[ifscb->first].buf);}
 ifscb->size_buffers -= ifscb->Tab_wav[ifscb->first].size;
 ifscb->Tab_wav[ifscb->first].deb = 0; ifscb->Tab_wav[ifscb->first].size = 0;
 ifscb->first = (ifscb->first+1)%ifscb->nb_buffers;
 ifscb->nb--;
}

//______________________________________________________________________________
void Info_for_sound_Drain_all(Info_for_sound_CB *ifscb)
{Info_for_sound_CB_Lock  (ifscb);
 Info_for_sound_CB_Commit_buffers(ifscb);
 while(Info_for_sound_CB_Nb_pkt(ifscb))
  {Info_for_sound_CB_Release(ifscb);
  }
 ifscb->first_t = 0;
 ifscb->last_temp = ifscb->last;
 Info_for_sound_CB_UnLock(ifscb);
}

//______________________________________________________________________________
void Info_for_sound_CB_Maj_size(Info_for_sound_CB *ifscb, const unsigned int index, const unsigned int d, const unsigned int s) {
 ifscb->size_buffers -= ifscb->Tab_wav[index].size - s;
 ifscb->Tab_wav[index].deb  = d;
 ifscb->Tab_wav[index].size = s;
}

//______________________________________________________________________________
void Info_for_sound_CB_Lock  (Info_for_sound_CB *ifscb)
{ifscb->mutex->lock();}

//______________________________________________________________________________
void Info_for_sound_CB_UnLock(Info_for_sound_CB *ifscb)
{ifscb->mutex->unlock();}

//______________________________________________________________________________
const int Info_for_sound_CB_First_index(Info_for_sound_CB *ifscb)
{return ifscb->first;
}

//______________________________________________________________________________
const int Info_for_sound_CB_Read(Info_for_sound_CB *ifscb, void *buff, const int dec_buf, const int len)
{if(ifscb->nb == 0) {return -1;}
 int len_wav     = ifscb->Tab_wav[ifscb->first].size;
 int nb_to_copy  = len_wav<len?len_wav:len;
 void *buf_src   = ifscb->Tab_wav[ifscb->first].buffer;
 int deb_buf_src = ifscb->Tab_wav[ifscb->first].deb;

 //printf("\n  pkt : %i\n  len : %i\n  dec_buff : %i\n  deb_buf_src : %i\n  memcpy(%p, %p, %i)\n"
 //	   , len_wav, len, dec_buf, deb_buf_src, (char*)buff+dec_buf, (char*)(buf_src) + deb_buf_src, nb_to_copy);
 memcpy((char*)buff+dec_buf, (char*)(buf_src) + deb_buf_src, nb_to_copy);
 
 if(nb_to_copy == len_wav)
  {//printf("  Info_for_sound_CB_Release\n"); 
   Info_for_sound_CB_Release(ifscb);
  } else {//printf("  Info_for_sound_CB_Maj_size (%i, %i)", ifscb->Tab_wav[ifscb->first].deb, ifscb->Tab_wav[ifscb->first].size);
          Info_for_sound_CB_Maj_size( ifscb
                                    , ifscb->first
                                    , ifscb->Tab_wav[ifscb->first].deb  + nb_to_copy
                                    , ifscb->Tab_wav[ifscb->first].size - nb_to_copy );
		 //XXX ALREADY DONE IN Info_for_sound_CB_Maj_size XXX ifscb->size_buffers -= nb_to_copy;
		  //printf(" => (%i, %i)\n", ifscb->Tab_wav[ifscb->first].deb, ifscb->Tab_wav[ifscb->first].size);
         }
 return nb_to_copy;
}
